import tkinter as tk
from tkinter import filedialog,StringVar,messagebox
import os,json

class viewRender():
    def __init__(self,ctx):
        self.ctx=ctx
        self.modDict=ctx.md.modDict
        self.main_view()
        self.md=ctx.md

    def entry_callback(self,e,target,key,dict=True):
        target[key]={"value":e.widget.get()}


    def value_in_window(self,obj,root,key):
        values_window=tk.Toplevel(root)
        values_window.rx=root.rx+100
        values_window.ry=root.ry+100
        values_window.geometry(f"768x512+{values_window.rx}+{values_window.ry}")
        values_window.title(key)
    
        row=0;col=0;maxcol=4;count=0
        for value in obj:
            count+=1
            if col>=maxcol:
                col=0
                row+=2

            if type(obj)==dict:
                label_value=tk.Label(values_window,text=value)
                label_value.grid(row=row,column=col,sticky='w')
                v_target = obj[value]
                if not type(v_target)==list:                    
                    txt = StringVar()
                    if 'value' in v_target:
                        txt.set(v_target['value'])
                        entry_value=tk.Entry(values_window,textvariable=txt)
                        entry_value.grid(row=row+1,column=col,sticky='w')            
                        entry_value.bind("<KeyRelease>",lambda event,target=obj,key=value:self.entry_callback(event,target,key))
                    else:
                        txt.set(v_target['text']['value'])
                        entry_value=tk.Entry(values_window,textvariable=txt)
                        entry_value.grid(row=row+1,column=col,sticky='w')            
                        entry_value.bind("<KeyRelease>",lambda event,target=v_target,key='text':self.entry_callback(event,target,key))




                        ss=0
                else:
                    btn_att=tk.Button(values_window,text='编辑详情',command=lambda obj=v_target,key=value:self.value_in_window(obj,values_window,key))               
                    btn_att.grid(row=row+1,column=col,sticky='w') 


            if type(obj)==list:
                label_value=tk.Label(values_window,text=f"value【{count}】")
                label_value.grid(row=row,column=col,sticky='w')
                if not 'reward' in value['value']:
                    txt = StringVar()
                    txt.set(value['value'])
                    entry_value=tk.Entry(values_window,textvariable=txt)
                    entry_value.grid(row=row+1,column=col,sticky='w')            
                    entry_value.bind("<KeyRelease>",lambda event,target=obj,key=count-1:self.entry_callback(event,target,key))
                else:
                    obj_reward = json.loads(value['value'])   
                    values_window.value1=value['value'] 
                    def json_save(obj_json):
                        obj[0]['value']=json.dumps(obj_json,ensure_ascii=False)
                    values_window.save=json_save
                    btn_att=tk.Button(values_window,text='编辑详情',command=lambda obj=obj_reward:self.obj_in_window(obj,values_window,True,"reward"))               
                    btn_att.grid(row=row+1,column=col,sticky='w') 
            col+=1






    def obj_in_window(self,obj_m,parent,jsontype=False,info=""):
        obj_window=tk.Toplevel(parent)
        obj_window.rx=parent.rx+100
        obj_window.ry=parent.ry+100

        obj_window.geometry(f"768x512+{obj_window.rx}+{obj_window.ry}")
        obj_window.title(info)

        if jsontype:
            def on_close():
                parent.save(obj_m)
                obj_window.destroy()

            obj_window.protocol("WM_DELETE_WINDOW",lambda: on_close())


        obj_dict={x['id']['value']:x for x in obj_m['items']}
        obj_listbox=tk.Listbox(obj_window,width=20,height=20)
        info_frame=tk.Frame(obj_window,width=512,height=20)
        obj_listbox.place(relx=0,rely=0)
        info_frame.place(relx=0.2,rely=0)
        
        info_frame.columnconfigure(0,minsize=200)
        info_frame.columnconfigure(1,minsize=200)
        info_frame.columnconfigure(2,minsize=200)

        def show_detail(obj,key):
            
            target = obj[key]
            #列表类型
            if type(target)==list:
                self.value_in_window(target,obj_window,key)
                return
            #对象类型
            if type(target)==dict:
                if 'items' in target:
                    self.obj_in_window(target,obj_window,info=key)          
                    return
            

            self.value_in_window(target,obj_window,key)
        #对象选择
        def obj_select(idx):
            row=0;col=0;maxcol=3
            obj=obj_m['items'][idx[0]]
            for att in obj:
                if col>=maxcol:
                    col=0
                    row+=2
                data_att=obj[att]  
                
                label_att=tk.Label(info_frame,text=att)   
                label_att.grid(row=row,column=col,sticky='w')         
                if 'value' in data_att:   
                    txt=StringVar()
                    txt.set(data_att['value'])
                    entry_att=tk.Entry(info_frame,textvariable=txt)        
                    entry_att.grid(row=row+1,column=col,sticky='w') 
                    
                    entry_att.bind("<KeyRelease>",lambda event,target=obj,key=att:self.entry_callback(event,target,key))
                else:
                    if 'text' in data_att and not 'costItem' in data_att:
                        txt=StringVar()
                        txt.set(data_att['text']['value'])
                        entry_att=tk.Entry(info_frame,textvariable=txt)        
                        entry_att.grid(row=row+1,column=col,sticky='w') 
                        entry_att.bind("<KeyRelease>",lambda event,target=data_att,key='text':self.entry_callback(event,target,key))

                    else:
                        btn_att=tk.Button(info_frame,text='编辑详情',command=lambda obj=obj_m['items'][idx[0]],key=att:show_detail(obj,key))               
                        btn_att.grid(row=row+1,column=col,sticky='w') 
                col+=1
        
        for key in obj_dict:
            obj_listbox.insert(tk.END,key)
            obj_listbox.bind("<Double-Button-1>",lambda e:obj_select(obj_listbox.curselection()))   

        def obj_new():
            res=self.md.obj_new(info)
            if res!={}:
                obj_m['items'].append(res)
                obj_listbox.insert(tk.END,res['id']['value'])
                idx=(len(obj_m['items'])-1,)
                obj_select(idx)



        btn_obj_new=tk.Button(obj_window,text="新增",command=lambda:obj_new())
        btn_obj_new.place(relx=0.2,rely=0.8)
        
        
        def obj_copy(idx):
            try:
                obj=obj_m['items'][idx]
                obj_new=self.md.obj_copy(obj,info)
                obj_m['items'].append(obj_new)
                obj_listbox.insert(tk.END,obj_new['id']['value'])
                idx_new = len(obj_m['items'])-1
                obj_select((idx_new,))
            except Exception as ex:
                messagebox.showerror("异常",ex)

        def obj_remove(idx):
            obj_m['items'].pop(idx)
            obj_listbox.delete(0,tk.END)
            for data in obj_m['items']:
                id=data['id']['value']
                obj_listbox.insert(tk.END,id)
            if len(obj_m['items'])>0:
                obj_select((0,))


        def popup_menu(event):
            # 获取鼠标所在的列表框项
            index = obj_listbox.nearest(event.y)
            # 清除先前选择的任何项
            obj_listbox.selection_clear(0, tk.END)
            # 选择新的项
            obj_listbox.selection_set(index)
            # 创建右键菜单
            menu = tk.Menu(obj_listbox, tearoff=0)
            # 清空右键菜单的选项
            menu.delete(0, tk.END)
            menu.add_command(label='复制',command=lambda x=index:obj_copy(x))
            # menu.add_command(label='粘贴')
            menu.add_command(label='删除',command=lambda x=index:obj_remove(x))
            menu.post(event.x_root, event.y_root)

        obj_listbox.bind('<Button-3>', lambda e :popup_menu(e))


        obj_select((0,))



    def mod_in_window(self,obj_mod):
        window_mod=tk.Toplevel(self.ctx)
        window_mod.rx=self.ctx.x_root+100
        window_mod.ry=self.ctx.y_root+100
        window_mod.geometry(f"640x512+{window_mod.rx}+{window_mod.ry}")
        path=obj_mod['path']
        mod_id=obj_mod['soleID']
        window_mod.title(f"MOD编辑器：【{obj_mod['name']}】")
        def on_close():
            idx=self.mod_opened.index(mod_id)
            self.mod_opened.pop(idx)
            window_mod.destroy()

        def on_save():
            data =window_mod.data
            self.md.modSave(path,data)
            messagebox.showinfo("保存结果","保存成功")

        window_mod.protocol("WM_DELETE_WINDOW",lambda: on_close())


        #读取MOD信息
        window_mod.data=self.md.modRead(path)

        #创建框架，用来渲染主要mod对象，配置列宽，渲染位置
        frame_obj=tk.Frame(window_mod,width=512,height=384)
        frame_obj.columnconfigure(0, minsize=200)
        frame_obj.columnconfigure(1, minsize=200)
        frame_obj.columnconfigure(2, minsize=200)
        frame_obj.place(relx=0.5,rely=0.2,anchor="center")

        #一个简易的mod信息存放框架
        frame_info=tk.Frame(window_mod)
        frame_info.place(relx=0.5,rely=0.8,anchor='center')

        #保存按钮
        btn_save = tk.Button(window_mod,text="保存",command=on_save)
        btn_save.place(relx=0.9,rely=0.9)

        #遍历mod中的主对象，并绑定按钮，单击时加载其数据到列表
        row=0;col=0;maxcol=3        
        for i in window_mod.data:
            obj_m=window_mod.data[i] 
            if col>= maxcol:
                row+=1
                col=0      
            #分别针对大对象创建编辑按钮，每个大对象都是一个字典，有个字列表为itmes，计算下数量显示在按钮上
            if type(obj_m) == dict:
                count=len(obj_m['items'])
                btn=tk.Button(frame_obj,text=f"{i}({count})",width=25,command=lambda obj=obj_m,key=i:self.obj_in_window(obj,window_mod,False,info=key))          
                btn.grid(row=row,column=col,sticky='w')                
            #有两个信息绑定到frame_info框架中
            else:
                label1=tk.Label(frame_info,text=f"{i}:【{obj_m}】")
                label1.grid(row=row,column=col,sticky='w')
            col+=1



    '''渲染主界面的函数'''
    def main_view(self):
        self.mod_opened=[]
        title_label = tk.Label(self.ctx, text="鬼谷八荒MOD制作辅助工具！！")
        title_label.place(relx=0.2,rely=0)

        #加载mod列表，并且绑定相关事件可以双击之后在新窗口渲染mod详情
        frame1=tk.Frame(self.ctx)
        frame1.grid(row=1,column=0,sticky='w',pady=10)
        frame2=tk.Frame(self.ctx)
        frame2.grid(row=2,column=0,sticky='w',pady=10)

        list_mod=tk.Listbox(frame2)
        list_mod.grid(row=2, column=0, columnspan=2, padx=0, pady=0, sticky="nsew")


        modlist=[]
        for k in self.modDict:
            name = self.modDict[k]['name']
            list_mod.insert(tk.END,name)
            modlist.append(k)

        def on_doubleclick(idx):#双击列表项定位mod信息
            mod_id=modlist[idx[0]]
            obj_mod=self.modDict[mod_id]
            if not mod_id in self.mod_opened:
                self.mod_opened.append(mod_id)
                print(f"准备打开：{obj_mod['name']}")
                self.mod_in_window(obj_mod)
            else:messagebox.showwarning("重复","mod已经打开，请勿重复开启")
            
        #双击直接进入编辑页面
        list_mod.bind("<Double-Button-1>",lambda e=None :on_doubleclick(list_mod.curselection()))   

        btn_base_load=tk.Button(self.ctx,text="BaseReload",command=self.ctx.md.inital_db)
        btn_base_load.place(relx=0.1,rely=0.9)


    staticmethod
    def config_view(ctx):

        def path_select(sv):
            path=filedialog.askdirectory()
            sv.set(path)

        def save():
            modPath=entry_mp.get()
            gamePath=entry_gp.get()
            if os.path.exists(modPath) and os.path.exists(gamePath):
                ctx.db['modPath']=modPath
                ctx.db['gamePath']=gamePath
                conf_win.destroy()
                ctx.gui_show()
            else:
                messagebox.showerror("路径异常","请检查两个文件夹路径是否正常")
        
        def cancel():
            conf_win.destroy()
            ctx.master.destroy()

        conf_win=tk.Toplevel(ctx.master)
        conf_win.geometry("640x128+200+200")
        conf_win.title("编辑配置")

        conf_win.grid_columnconfigure(0,minsize=20)
        conf_win.grid_columnconfigure(1,minsize=80)
        conf_win.grid_columnconfigure(2,minsize=10)

        label_mp=tk.Label(conf_win,text="MOD路径")
        label_gp=tk.Label(conf_win,text="游戏路径")
        sv_mp=StringVar()
        sv_gp=StringVar()


        entry_mp=tk.Entry(conf_win,width=70,textvariable=sv_mp)
        entry_gp=tk.Entry(conf_win,width=70,textvariable=sv_gp)



        btn_mp=tk.Button(conf_win,width=10,text="选择目录",command=lambda sv=sv_mp:path_select(sv))
        btn_gp=tk.Button(conf_win,width=10,text="选择目录",command=lambda sv=sv_gp:path_select(sv))

        label_mp.grid(row=1,column=0,sticky='w')
        entry_mp.grid(row=1,column=1,sticky='w')
        btn_mp.grid(row=1,column=2,sticky='w')
        label_gp.grid(row=2,column=0,sticky='w')
        entry_gp.grid(row=2,column=1,sticky='w')
        btn_gp.grid(row=2,column=2,sticky='w')






        btn_save=tk.Button(conf_win,text="保存",width=25,command=save)
        btn_cancel=tk.Button(conf_win,text="取消",width=25,command=cancel)
        btn_save.place(relx=0.1,rely=0.5)
        btn_cancel.place(relx=0.5,rely=0.5)